package com.runfast.paotui.service.impl;


import com.runfast.common.exception.BaseException;
import com.runfast.common.service.*;
import com.runfast.common.web.entity.Result;
import com.runfast.common.web.entity.ResultCode;
import com.runfast.paotui.dao.mapper.OrderMapper;
import com.runfast.paotui.dao.model.*;
import com.runfast.paotui.entity.BicyclingResponse;

import com.runfast.paotui.mq.AmqpClient;
import com.runfast.paotui.service.*;
import com.runfast.paotui.task.async.MessagePushTask;
import com.runfast.paotui.utils.AmapUtil;
import com.runfast.paotui.utils.OrderUtil;
import com.runfast.paotui.web.dto.OrderDto;
import com.runfast.pay.service.PayService;
import com.runfast.waimai.dao.model.RunfastGoodsSellRecord;
import com.runfast.waimai.util.PageBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Lazy(false)
public class OrderServiceImpl extends BaseService<Order, Integer, OrderExample> implements OrderService {
    @Resource
    OrderMapper orderMapper;

    @Autowired
    private RunfastDeliverCostService deliverCostService;

    @Autowired
    private RunfastCuseraddressService cuseraddressService;

    @Autowired
    private RunfastAgentbusinessService agentbusinessService;


    @Autowired
    private RunfastCuserService cuserService;


    @Autowired
    private OrderStatusHistoryService orderStatusHistoryService;


    @Autowired
    private MessagePushTask messagePushTask;

    @Autowired
    private RunfastShopperService shopperService;

    @Autowired
    @Lazy
    private PayService payService;

    @Autowired
    private AmqpClient amqpClient;

    @Override
    public List<Order> findByShopperid(Integer id) {
        return orderMapper.findByShopperid(id);
    }

    @Override
    public PageBean<Order> getPageBean4Driver(Integer pageSize, Integer page, Integer otype, Integer shopperId, Integer agentid, Integer teamid) {
//    created=下单成功 canceled=取消订单  paid=接单成功 taken=排列 completed==订单完成
        Order order=new Order();
        if(otype==1){
            order.setStatus(Order.Status.CREATED);//1：客户已付款
        }else if(otype==-10){
            order.setStatus(Order.Status.PAID);//2：商品接单
        }else if(otype==2){
            order.setStatus(Order.Status.PAID);//4：商品打包
        }else if(otype==4){
            order.setStatus(Order.Status.COMPLETED);//5：商品送达
        }
        else {
            order.setDriverId(shopperId);//设置shopperid
        }
        List<Order>list= orderMapper.findListPageBean(pageSize,page,otype,shopperId,agentid,teamid);

        int count=orderMapper.findCount(pageSize,page,otype,shopperId,agentid,teamid);
        PageBean<Order> pageBean=new PageBean<Order>();
        pageBean.setAllRow(count);// 总记录数
        pageBean.setCurrentPage(pageSize+1);// 当前页,每页面记录数为2
        pageBean.setTotalPage(count/2);// 总页数
        pageBean.setData(list);//设置当前页面的数据集合
      /*  private int allRow; // 总记录数
        private int totalPage; // 总页数
        private int currentPage; // 当前页
        private int pageSize = 2; // 每页记录数*/


        return pageBean;
    }

    @Override
    public List<Order> findByShopperidAndStatus(Integer driverId, Integer status) {
        return orderMapper.findByShopperidAndStatus(driverId,  status);
    }

    @Override
    public Order findByUseridAndCode(Integer userid,String orderNo) {
        return orderMapper.findByUseridAndCode(userid,orderNo);
    }

    @Override
    public Order findByShopperidAndCode(Integer shopperid, String orderNo) {
        return orderMapper.findByShopperidAndCode(shopperid, orderNo);
    }

    @Override
    public Order get(Integer id) {
        return orderMapper.get(id);
    }

    @Override
    public Result confirm(Order order) {
        Validate.notNull(order);
        Validate.notNull(order.getCuserId(), "order.cuserId 不能为null");
       Order.Type orderType = order.getType();
        Validate.notNull(orderType, "order.type 不能为null");
        if (orderType == Order.Type.DAIGOU) {
            validate(order, Order.Daigou.class);
        }

        if (orderType == Order.Type.QUSONGJIAN) {
            validate(order, Order.Qusongjian.class);
        }

        Validate.notNull(order.getToId(), "order.toId 不能为null");

        RunfastCuseraddress toAddress = cuseraddressService.selectByPrimaryKey(order.getToId());
        if (toAddress == null) return Result.fail(ResultCode.FAIL, "不存在toId对应的收货地址");
        Double toLng = Double.valueOf(toAddress.getLongitude());
        Double toLat = Double.valueOf(toAddress.getLatitude());

        String destination = toLng + "," + toLat;
        RunfastAgentbusiness agentNearBy = null;

        Integer deliveryCost = null;

        if (orderType == Order.Type.DAIGOU) {
            Order.FromType fromType = order.getFromType();
            if (fromType == Order.FromType.SPECIFIED) {
                validate(order,  Order.Specified.class);
                Double fromLng = order.getFromLng();
                Double fromLat = order.getFromLat();

                String origin = fromLng + "," + fromLat;


                agentNearBy = agentbusinessService.getAgentNearBy(fromLng, fromLat);
                if (agentNearBy != null) {
                    RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());

                    BicyclingResponse bicyclingResponse = AmapUtil.bicycling(origin, destination);
                    if (bicyclingResponse.getErrcode() == 0) {
                        BicyclingResponse.Data data = bicyclingResponse.getData();
                        List<BicyclingResponse.Path> paths = data.getPaths();
                        if (!paths.isEmpty()) {
                            BicyclingResponse.Path path = paths.get(0);
                            Integer distance = path.getDistance();
                            Integer duration = path.getDuration();

                            order.setDistance(distance);
                            order.setDeliveryDuration((int) Math.ceil(duration / 60D));
                            DeliveryCost deliveryFee= deliverCostService.getDeliveryCost(order.getDistance(), null, defaultDeliveryTemplate);
                            deliveryCost = deliveryFee.getDeliveryFee();
                        }
                    } else {
                        throw new RuntimeException(bicyclingResponse.getErrdetail());
                    }


                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
                }


            } else if (fromType == Order.FromType.NEARBY) {
                validate(order,  Order.NearBy.class);

                agentNearBy = agentbusinessService.getAgentNearBy(order.getUserLng(), order.getUserLat());
                if (agentNearBy != null) {

                    RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());
                    Double nocharge = defaultDeliveryTemplate.getNoCharge() == null ? 0d : defaultDeliveryTemplate.getNoCharge();

                    //转换为以米为单位
                    Integer baseDistance = BigDecimal.valueOf(nocharge).multiply(BigDecimal.valueOf(1000)).intValue();
                    order.setDistance(baseDistance);

                    double speed = defaultDeliveryTemplate.getSpeed() == null ? 1d : defaultDeliveryTemplate.getSpeed();
                    int duration = (int) Math.ceil(baseDistance * speed / 100);
                    order.setDeliveryDuration(duration < 15 ? 15 : duration);
                    DeliveryCost deliveryFee = deliverCostService.getDeliveryCost(null, null, defaultDeliveryTemplate);
                    deliveryCost = deliveryFee.getDeliveryFee();
                } else {
                    return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
                }

            }
        }
        if (orderType == Order.Type.QUSONGJIAN) {
            validate(order,  Order.Qusongjian.class);

            Integer fromId = order.getFromId();

            RunfastCuseraddress fromAddress = cuseraddressService.selectByPrimaryKey(fromId);
            if (fromAddress == null) return Result.fail(ResultCode.FAIL, "不存在fromId对应的取货地址");
            Double fromLng = Double.valueOf(fromAddress.getLongitude());
            Double fromLat = Double.valueOf(fromAddress.getLatitude());
            String origin = fromLng + "," + fromLat;


            agentNearBy = agentbusinessService.getAgentNearBy(fromLng, fromLat);
            if (agentNearBy != null) {
                RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());

                BicyclingResponse bicyclingResponse = AmapUtil.bicycling(origin, destination);
                if (bicyclingResponse != null && bicyclingResponse.getErrcode() == 0) {
                    BicyclingResponse.Data data = bicyclingResponse.getData();
                    List<BicyclingResponse.Path> paths = data.getPaths();
                    BicyclingResponse.Path path = paths.get(0);
                    Integer distance = path.getDistance();
                    Integer duration = path.getDuration();

                    order.setDistance(distance);
                    order.setDeliveryDuration((int) Math.ceil(duration / 60d));
                    DeliveryCost deliveryFee = deliverCostService.getDeliveryCost(order.getDistance(), null, defaultDeliveryTemplate);
                    deliveryCost = deliveryFee.getDeliveryFee();
                } else {
                    throw new RuntimeException(bicyclingResponse.getErrdetail());

                }

            } else {
                return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
            }

        }


        order.setDeliveryCost(deliveryCost);

        Integer amountPayable = 0;
        amountPayable = deliveryCost;
        order.setAmountPayable(amountPayable);


        String orderNo = OrderUtil.generateOrderNo("p");
        order.setOrderNo(orderNo);
        order.setStatus(Order.Status.CREATED);

        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        order.setAgentId(agentNearBy.getId());

        this.insertSelective(order);

        OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
        orderStatusHistory.setStatus(Order.Status.CREATED);
        orderStatusHistory.setOrderId(order.getId());
        orderStatusHistory.setCreateTime(new Date());
        orderStatusHistory.setUpdateTime(new Date());
        orderStatusHistoryService.insertSelective(orderStatusHistory);

        messagePushTask.newOrderNotify(orderNo, agentNearBy.getId());

        amqpClient.publish(order);
        return Result.ok("下单成功", order);

    }

    /**
     *
     * @param driverId
     * @param orderId
     * @return
     */
    @Override
    public Result take(Integer driverId, Integer orderId) {
        Validate.notNull(driverId, "driverId 不能为null");
        Validate.notNull(orderId, "orderId 不能为null");

        Order order = this.selectByPrimaryKey(orderId);
        Validate.notNull(order, "不存在该订单");

        Order.Status status = order.getStatus();
        if (status != Order.Status.PAID) {
            return Result.fail(ResultCode.ILLEGAL_OPERATION, "非法操作，订单当前状态为已支付才能接单");
        }

        Integer agentId = order.getAgentId();

        RunfastAgentbusiness agentbusiness = agentbusinessService.selectByPrimaryKey(agentId);
        BigDecimal agentbusinessCoefficient = agentbusiness.getCoefficient();


        RunfastShopper shopper = shopperService.selectByPrimaryKey(driverId);
        BigDecimal shopperCoefficient = shopper.getCoefficient();


        if (agentbusinessCoefficient != null && shopperCoefficient != null && shopperCoefficient.subtract(agentbusinessCoefficient).doubleValue() >= 0) {

            int plateformIncome = agentbusinessCoefficient.multiply(BigDecimal.valueOf(order.getAmountPaid())).intValue();

            int agentIncome = shopperCoefficient.multiply(BigDecimal.valueOf(order.getAmountPaid())).subtract(BigDecimal.valueOf(plateformIncome)).intValue();

            int driverIncome = order.getAmountPaid() - plateformIncome - agentIncome;

            Order orderUpdate = new Order();
            orderUpdate
                    .withStatus(Order.Status.TAKEN)
                    .withTaken(true)
                    .withTimeTaken(new Date())
                    .withDriverId(driverId)
                    .withDriverIncome(driverIncome)
                    .withAgentIncome(agentIncome)
                    .withPlateformIncome(plateformIncome)
                    .withUpdateTime(new Date());

            OrderExample orderExample = new OrderExample();
            orderExample.createCriteria().andIdEqualTo(orderId)
                    .andStatusEqualTo(Order.Status.PAID.ordinal());
            int count = this.updateByExampleSelective(orderUpdate, orderExample);
            if (count == 1) {

                messagePushTask.takenOrderNotity(order.getOrderNo(), order.getCuserId());

                return Result.ok("接单成功");
            } else {
                return Result.fail(ResultCode.FAIL, "没有可处理的订单");
            }

        } else {
            return Result.fail(ResultCode.PARAMETER_ERROR, "agentbusiness.coefficient和shopper.coefficient不能为null，且shopper.coefficient必须大于等于agentbusiness.coefficient");
        }


    }

    @Override
    public Result cancel(Integer userId, Integer orderId) {

        Validate.notNull(userId, "userId 不能为null");
        Validate.notNull(orderId, "orderId 不能为null");

        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andCuserIdEqualTo(userId)
                .andIdEqualTo(orderId);

        List<Order> orders = this.selectByExample(orderExample);
        if (orders.isEmpty()) return Result.fail(ResultCode.FAIL, "该用户下不存在要取消的订单");

        Order order = orders.get(0);
        Order.Status status = order.getStatus();
        if (status == Order.Status.CREATED || status == Order.Status.PAID) {

            Order orderUpdate = new Order();
            orderUpdate
                    .withStatus(Order.Status.CANCELED)
                    .withUpdateTime(new Date());

            OrderExample orderExampleUpdate = new OrderExample();
            orderExampleUpdate.createCriteria().andIdEqualTo(orderId)
                    .andStatusEqualTo(status.ordinal());

            int update = this.updateByExampleSelective(orderUpdate, orderExampleUpdate);

            if (update == 1) {
                if (status == Order.Status.PAID) {

                    Result result = payService.applyRefund(order.getOrderNo(), "", order.getAmountPaid());
                    if (result.isSuccess()) {
                        return Result.ok("取消订单成功，支付金额稍后将原路返还");
                    } else {
                        return Result.fail(ResultCode.FAIL, "取消订单失败,原因：" + result.getErrorMsg());
                    }
                } else {
                    return Result.ok("取消订单成功");
                }

            } else {
                return Result.fail(ResultCode.FAIL, "该用户下不存在要取消的订单");
            }

        } else {
            return Result.fail(ResultCode.FAIL, "骑手已接单，只能取消还未处理的订单");
        }


    }

    @Override
    public List<Map<String, Integer>> selectIdUserIdByExample(OrderExample example) {
        return mapper.selectIdUserIdByExample(example);
    }

    @Override
    public Result fillIn(Order order) {
        Validate.notNull(order, "order 不能为null");
        Validate.notNull(order.getType(), "order.type 不能为null");
        Validate.notNull(order.getUserLng(), "order.userLng 不能为null");
        Validate.notNull(order.getUserLat(), "order.userLat 不能为null");


        HashMap<String, Object> data = new HashMap<>();
        Order.Type type = order.getType();
        Integer toId = order.getToId();
        if (toId != null) {
            RunfastCuseraddress toAddress = cuseraddressService.selectByPrimaryKey(toId);

            if (toAddress == null) return Result.fail(ResultCode.FAIL, "不存在toId对应的收货地址");

            Double toLng = Double.valueOf(toAddress.getLongitude());
            Double toLat = Double.valueOf(toAddress.getLatitude());

            String destination = toLng + "," + toLat;

            if (type == Order.Type.DAIGOU) {
                Order.FromType fromType = order.getFromType();
                if (fromType != null) {
                    if (fromType == Order.FromType.SPECIFIED) {
                        Double fromLng = order.getFromLng();
                        Double fromLat = order.getFromLat();

                        if (fromLng != null && fromLat != null) {
                            String origin = fromLng + "," + fromLat;
                            RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearBy(fromLng, fromLat);

                            if (agentNearBy != null) {
                                RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());

                                BicyclingResponse bicyclingResponse = AmapUtil.bicycling(origin, destination);
                                if (bicyclingResponse.getErrcode() == 0) {
                                    BicyclingResponse.Data bycyclingData = bicyclingResponse.getData();
                                    List<BicyclingResponse.Path> paths = bycyclingData.getPaths();
                                    if (!paths.isEmpty()) {
                                        BicyclingResponse.Path path = paths.get(0);
                                        Integer distance = path.getDistance();
                                        Integer duration = path.getDuration();

                                        Integer deliveryDuration = (int) Math.ceil(duration / 60D);

                                        data.put("distance", distance);
                                        data.put("deliveryDuration", deliveryDuration < 15 ? 15 : deliveryDuration);
                                        data.putAll(BeanMap.create(deliverCostService.getDeliveryCost(distance, null, defaultDeliveryTemplate)));

                                        return Result.ok("", data);
                                    } else {
                                        throw new BaseException(ResultCode.SYSTEM_BUSY);
                                    }
                                } else {
                                    throw new RuntimeException(bicyclingResponse.getErrdetail());
                                }


                            } else {
                                return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
                            }
                        }

                    }
                }

            } else {
                Integer fromId = order.getFromId();

                if (fromId != null) {
                    RunfastCuseraddress fromAddress = cuseraddressService.selectByPrimaryKey(fromId);
                    if (fromAddress == null) return Result.fail(ResultCode.FAIL, "不存在fromId对应的取货地址");
                    Double fromLng = Double.valueOf(fromAddress.getLongitude());
                    Double fromLat = Double.valueOf(fromAddress.getLatitude());
                    String origin = fromLng + "," + fromLat;


                    RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearBy(fromLng, fromLat);
                    if (agentNearBy != null) {
                        RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());

                        BicyclingResponse bicyclingResponse = AmapUtil.bicycling(origin, destination);
                        if (bicyclingResponse != null && bicyclingResponse.getErrcode() == 0) {
                            BicyclingResponse.Data bycyclingData = bicyclingResponse.getData();
                            List<BicyclingResponse.Path> paths = bycyclingData.getPaths();
                            BicyclingResponse.Path path = paths.get(0);
                            Integer distance = path.getDistance();
                            Integer duration = path.getDuration();

                            Integer deliveryDuration = (int) Math.ceil(duration / 60d);

                            data.put("distance", distance);
                            data.put("deliveryDuration", deliveryDuration < 15 ? 15 : deliveryDuration);
                            data.putAll(BeanMap.create(deliverCostService.getDeliveryCost(distance, order.getGoodsWeight(), defaultDeliveryTemplate)));

                            return Result.ok("", data);
                        } else {
                            throw new RuntimeException(bicyclingResponse.getErrdetail());

                        }

                    } else {
                        return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
                    }
                }

            }

        }


        RunfastAgentbusiness agentNearBy = agentbusinessService.getAgentNearBy(order.getUserLng(), order.getUserLat());
        if (agentNearBy != null) {

            RunfastDeliverCost defaultDeliveryTemplate = deliverCostService.getDefaultDeliveryTemplate(agentNearBy.getId());
            Double nocharge = defaultDeliveryTemplate.getNoCharge() == null ? 0d : defaultDeliveryTemplate.getNoCharge();

            //转换为以米为单位
            Integer baseDistance = BigDecimal.valueOf(nocharge).multiply(BigDecimal.valueOf(1000)).intValue();

            double speed = defaultDeliveryTemplate.getSpeed() == null ? 1d : defaultDeliveryTemplate.getSpeed();
            int duration = (int) Math.ceil(baseDistance * speed / 100);
//                            order.setDeliveryDuration(duration < 15 ? 15 : duration);
            Integer deliveryDuration = duration < 15 ? 15 : duration;

            data.put("distance", baseDistance);
            data.put("deliveryDuration", deliveryDuration);
            data.putAll(BeanMap.create(deliverCostService.getDeliveryCost(null, type == Order.Type.QUSONGJIAN ? order.getGoodsWeight() : null, defaultDeliveryTemplate)));

            return Result.ok("", data);

        } else {
            return Result.fail(ResultCode.AGENT_NEAR_BY_NOT_EXIST);
        }

    }

    @Override
    public OrderDto toOrderDto(Order order) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        OrderDto orderDto = new OrderDto();
        Order.Type type = order.getType();

        PropertyUtils.copyProperties(orderDto, order);
        Integer driverId = order.getDriverId();
        if(driverId!=null){
            RunfastShopper runfastShopper = shopperService.selectByPrimaryKey(driverId);

            orderDto.setDriverName(runfastShopper.getName());
            orderDto.setDriverMobile(runfastShopper.getMunber());
        }

        switch (type){
            case DAIGOU:
                Order.FromType fromType = order.getFromType();
                if(fromType==Order.FromType.NEARBY){
                    orderDto.setFromAddress("就近购买");
                }
                break;
            case QUSONGJIAN:
                Integer fromId = order.getFromId();

                RunfastCuseraddress runfastCuseraddress = cuseraddressService.selectByPrimaryKey(fromId);
                orderDto.setFromAddress(runfastCuseraddress.getAddress());
                orderDto.setFromName(runfastCuseraddress.getCname());
                orderDto.setFromMobile(runfastCuseraddress.getMobile());
                break;
        }

        Integer toId = order.getToId();

        RunfastCuseraddress runfastCuseraddress = cuseraddressService.selectByPrimaryKey(toId);
        orderDto.setToAddress(runfastCuseraddress.getAddress());
        orderDto.setToName(runfastCuseraddress.getCname());
        orderDto.setToMobile(runfastCuseraddress.getMobile());

        return orderDto;
    }

    @Override
    public void updateStatusAndTime(Order orderuser2) {
        orderMapper.updateStatusAndTime(orderuser2);
    }

}